package com.kanesoft.android.gdx.widgets.sprites;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.kanesoft.android.gdx.widgets.GdxWidgets;
import com.kanesoft.android.gdx.widgets.WidgetEvents;

public class SpriteWidget extends GdxWidgets {

    private float animationTime;
    private float animationDuration;

    private float drawPosX;
    private float drawPosY;
    private float animePosX;
    private float animePosY;
    private float animeCurrentWidth;
    private float animeCurrentHeight;

    
    private float cameraOffsetX;
    private float cameraOffsetY;
    
    private float animeScaleX;
    private float animeScaleY;
    private float animeFlippedPosX;
    private float animeFlippedPosY;

    private SpriteBatch spriteBatch;
    private Animation animeAnimation;

    private TextureRegion animeFrame;
    private SpriteInfo spriteInfo;

    private boolean flipHorizontal;
    private boolean flipVertical;
    private boolean flippedPosInitialized;

    private boolean animationInLoop;
    private float rotationAngle;

    public float userTag;

    public SpriteWidget(float x, float y, float scaleX, float scaleY, SpriteInfo info, WidgetEvents eventsHandler) {
        super(eventsHandler);
        setSpritePosition(x, y);
        setSpriteSize(scaleX, scaleY);
        setSpriteInfo(info);
        spriteBatch = new SpriteBatch();
    }

    public void setSpriteInfo(SpriteInfo info) {
        if (info == null) return;
        animationTime = 0;
        spriteInfo = info;
        animationDuration = spriteInfo.getAnimationDuration();
        animeAnimation = spriteInfo.getSpriteAnimation(flipHorizontal, flipVertical);
    }

    public SpriteInfo getSpriteInfo() {
        return spriteInfo;
    }

    public void setRotationAngle(float angle) {
        System.err.println("ANGLE = " + angle);
        rotationAngle = angle;
    }
    
    public void setSpritePosition(float x, float y) {
        animePosX = x;
        animePosY = y;
    }

    public float getPoxX() {
        return animePosX;
    }

    public float getPoxY() {
        return animePosY;
    }

    public void setSpriteSize(float scaleX, float scaleY) {
        if (scaleX < 0) scaleX = 0;
        if (scaleY < 0) scaleY = 0;

        animeScaleX = scaleX;
        animeScaleY = scaleY;
    }

    public float getScaleX() {
        return animeScaleX;
    }

    public float getScaleY() {
        return animeScaleY;
    }

    public void setNewFrameDuration(float sleepTime) {
        if (spriteInfo == null) return;
        animeAnimation.frameDuration = sleepTime;
    }

    public void flipSpriteHorizontal() {
        flipHorizontal = !flipHorizontal;
        setSpriteInfo(spriteInfo);
    }

    public void setFlipSpriteHorizontal(boolean flip) {
        if (flip == flipHorizontal) return;
        flipSpriteHorizontal();
    }

    public void flipSpriteVertical() {
        flipVertical = !flipVertical;
        setSpriteInfo(spriteInfo);
    }

    public void setFlipSpriteVertical(boolean flip) {
        if (flip == flipVertical) return;
        flipSpriteVertical();
    }

    public void setAnimationInLoop(boolean loop) {
        animationInLoop = loop;
    }

    public float[] getWidgetVertices() {
        float[] vertices = new float[4];
        vertices[0] = drawPosX;
        vertices[1] = drawPosY;
        vertices[2] = drawPosX + animeCurrentWidth;
        vertices[3] = drawPosY + animeCurrentHeight;

        return vertices;
    }

    public boolean isWidgetOverlapping(GdxWidgets widget) {
        if (spriteInfo == null) return false;

        float[] localSpriteareaVertices = getReduceArea(getWidgetVertices(), 0.8f);
        float[] remoteSpriteareaVertices = getReduceArea(widget.getWidgetVertices(), 0.8f);

        if (localSpriteareaVertices[2] <= remoteSpriteareaVertices[0]) return false;
        if (localSpriteareaVertices[3] <= remoteSpriteareaVertices[1]) return false;
        if (remoteSpriteareaVertices[2] <= localSpriteareaVertices[0]) return false;
        if (remoteSpriteareaVertices[3] <= localSpriteareaVertices[1]) return false;

        return true;
    }

    private float[] getReduceArea(float[] vertices, float percent) {
        float[] new_vertices = vertices;

        float width = vertices[2] - vertices[0];
        float height = vertices[3] - vertices[1];

        float new_width = width * percent;
        float new_height = height * percent;

        float offset_x = (width - new_width) / 2;
        float offset_y = (height - new_height) / 2;

        new_vertices[0] = new_vertices[0] + offset_x;
        new_vertices[1] = new_vertices[1] + offset_y;
        new_vertices[2] = new_vertices[0] + new_width;
        new_vertices[3] = new_vertices[1] + new_height;

        return new_vertices;
    }

    private void drawAnimation(float deltaTime) {
        drawPosX = animePosX + cameraOffsetX;
        drawPosY = animePosY + cameraOffsetY;
        
        spriteBatch.begin();
        animeFrame = animeAnimation.getKeyFrame(animationTime, animationInLoop);

        animeCurrentWidth = animeFrame.getRegionWidth() * animeScaleX;
        animeCurrentHeight = animeFrame.getRegionHeight() * animeScaleY;

        if (animeCurrentWidth < 0) animeCurrentWidth = animeCurrentWidth * -1;
        if (animeCurrentHeight < 0) animeCurrentHeight = animeCurrentHeight * -1;

        if (flippedPosInitialized == false) {
            flippedPosInitialized = true;
            animeFlippedPosX = animeCurrentWidth;
            animeFlippedPosY = animeCurrentHeight;
        }

        if (flipHorizontal) {
            drawPosX = animePosX + animeFlippedPosX - animeCurrentWidth + cameraOffsetX;
        }

        if (flipVertical) {
            drawPosY = animePosY + animeFlippedPosY - animeCurrentHeight + cameraOffsetY;
        }


        spriteBatch.draw(animeFrame, drawPosX, drawPosY, 0, 0, animeCurrentWidth, animeCurrentHeight, 1, 1,
                rotationAngle);

        spriteBatch.end();

        if (spriteEventsHandler != null) {
            spriteEventsHandler.actualAttackBehavior(spriteInfo.isAttackFrame(animeFrame));
        }
    }

    private void draw(float deltaTime) {
        if (spriteInfo == null) return;
        if (enabled == false) return;

        if ((animationTime == 0) && (deltaTime > 0)) {
            drawAnimation(0);
        }

        animationTime += deltaTime;

        drawAnimation(animationTime);

        if (spriteEventsHandler != null) {
            if ((animationInLoop == false) && (animationTime >= animationDuration)) {
                spriteEventsHandler.onAnimationComplete();
            }

            if ((drawPosX > Gdx.graphics.getWidth()) || (drawPosX + animeCurrentWidth < 0)
                    || (drawPosY > Gdx.graphics.getHeight()) || (drawPosY + animeCurrentHeight < 0)) {
                spriteEventsHandler.onSpriteOutOfScreen();
            }
        }
    }
    
    @Override
    public void draw(float deltaTime, float cameraOffsetX, float cameraOffsetY) {
        this.cameraOffsetX = cameraOffsetX;
        this.cameraOffsetY = cameraOffsetY;
        
        draw(deltaTime);
    }

    @Override
    public void onPressDown(int x, int y) {
        if ((x < animePosX) || (y < animePosY) || (x > animePosX + animeCurrentWidth)
                || (y > animePosY + animeCurrentHeight)) { return; }
    }

    @Override
    public void onPressUp(int x, int y) {

        if ((x < animePosX) || (y < animePosY) || (x > animePosX + animeCurrentWidth)
                || (y > animePosY + animeCurrentHeight)) { return; }

        if (spriteEventsHandler != null) {

            spriteEventsHandler.onClick();
        }
    }

    @Override
    public void destroyWidget() {
        spriteBatch.dispose();
    }

}
